﻿using System.Collections;
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using UnityEngine;

namespace Nirvana
{

    /// <summary>
    /// 管理LoadTask下载ab，并从本地加载
    /// </summary>
    public sealed class AssetBundleLoadTaskMgr
    {
        private AssetBundleCache abcache;
        private TaskManager taskMgr;
        private LinkedList<AssetBundleLoadTask> abLoadTaskList = new LinkedList<AssetBundleLoadTask>();
        public string DownUrl { get; set; }
        public string Version { get; set; }
        public bool IngoreHash { get; set; }

        public AssetBundleLoadTaskMgr(AssetBundleCache cache,TaskManager taskManager)
        {
            this.abcache = cache;
            this.taskMgr = taskManager;
        }
        /// <summary>
        /// 下载Ab
        /// </summary>
        public WaitLoadAssetBundle UpdateBundle(string bundlename,Hash128 hash)
        {
            if (!hash.isValid)
            {
                return new WaitLoadAssetBundle("Bunlde Hash is invalid");
            }

            if (this.abcache.IsValidateCache(bundlename, hash))
            {
                return new WaitLoadAssetBundle();
            }
            //查找已存在的ab，等待下载完成
            foreach(var p in abLoadTaskList)
            {
                if(p.AssetBundleName == bundlename&& p.Hash == hash)
                {
                    return new WaitLoadAssetBundle(p);
                }
            }

            string path = GetAssetBundePath(bundlename,this.Version);
            var task = new AssetBundleLoadTask(false, this.taskMgr, path, this.abcache, bundlename);
            this.abLoadTaskList.AddLast(task);
            this.taskMgr.AddTask(task, false);//放入任务管理器，并开始执行下载

            return new WaitLoadAssetBundle(task);
        }

        /// <summary>
        /// 本地加载Ab
        /// </summary>
        public WaitLoadAssetBundleAsync LoadBundleAsync(string bundle,bool isSync)
        {
            //同步加载，直接返回
            if (isSync)
            {
                AssetBundle ab = this.abcache.LoadFromFile(bundle);
                return new WaitLoadAssetBundleAsync(ab);
            }

            var abRequest = this.abcache.LoadFromFileAsync(bundle);
            if (abRequest == null) return null;
            var task = new AssetBundleLoadTask(this.abcache, abRequest, bundle);
            this.abLoadTaskList.AddFirst(task);
            return new WaitLoadAssetBundleAsync(task);
        }

        public WaitLoadAssetBundleAsync LoadBundleAsync(string bundle,Hash128 hash,bool isSync)
        {
            //同步加载，直接返回
            if (isSync)
            {
                AssetBundle ab = this.abcache.LoadFromFile(bundle,hash,this.IngoreHash);
                return new WaitLoadAssetBundleAsync(ab);
            }

            var abRequest = this.abcache.LoadFromFileAsync(bundle, hash, this.IngoreHash);
            if (abRequest == null) return null;
            var task = new AssetBundleLoadTask(this.abcache, abRequest, bundle,hash);
            this.abLoadTaskList.AddFirst(task);
            return new WaitLoadAssetBundleAsync(task);
        }

        public WaitLoadAssetBundleAsync LoadBundle(string bundle,Hash128 hash,bool isIngoreHash)
        {
            if (this.IngoreHash)
            {
                return this.LoadBundleAsync(bundle, hash, isIngoreHash);
            }

            if (this.abcache.IsValidateCache(bundle, hash))
            {
                return this.LoadBundleAsync(bundle, hash, isIngoreHash);
            }

            foreach(var p in abLoadTaskList)
            {
                if (p.AssetBundleName == bundle && p.Hash == hash)
                {
                    p.IsLoading = false;
                    return new WaitLoadAssetBundleAsync(p);
                }
            }

            string path = GetAssetBundePath(bundle, hash.ToString());
            var task = new AssetBundleLoadTask(false, this.taskMgr, path, this.abcache, bundle,hash);
            this.abLoadTaskList.AddLast(task);
            this.taskMgr.AddTask(task, false);//放入任务管理器，并开始执行下载

            return new WaitLoadAssetBundleAsync(task);

        }

        public WaitLoadAssetBundleAsync LoadBundle(string bundle)
        {
            foreach (var p in abLoadTaskList)
            {
                if (p.AssetBundleName == bundle)
                {
                    p.IsLoading = false;
                    return new WaitLoadAssetBundleAsync(p);
                }
            }

            string path = GetAssetBundePath(bundle, this.Version);
            var task = new AssetBundleLoadTask(false, this.taskMgr, path, this.abcache, bundle);
            this.abLoadTaskList.AddLast(task);
            this.taskMgr.AddTask(task, false);//放入任务管理器，并开始执行下载

            return new WaitLoadAssetBundleAsync(task);
        }

        public bool IsValidateCache(string bundle ,Hash128 hash)
        {
            return this.abcache.IsValidateCache(bundle, hash);
        }
        /// <summary>
        /// 设置任务开始下载
        /// </summary>
        public void SetStartLoadingState()
        {
            foreach (var p in abLoadTaskList)
            {
                if (p.IsHaveRequest())
                {
                    p.IsLoading = true;
                }
            }
        }

        public void ExcuteTask()
        {
            LinkedListNode<AssetBundleLoadTask> next;
            for(LinkedListNode<AssetBundleLoadTask> node = this.abLoadTaskList.First;node != null;node = next)
            {
                next = node.Next;
                var task = node.Value;
                if (!task.ExcuteLoadTask())
                {
                    this.abLoadTaskList.Remove(node);
                }
            }
            AssetBundleLoadTask.ResetDownCount();
        }

        /// <summary>
        /// 从本地缓存中加载AB
        /// </summary>
        public AssetBundle LoadFromFile(string bundle)
        {
            return this.abcache.LoadFromFile(bundle);
        }

        public AssetBundle LoadFromFile(string bundle,Hash128 hash)
        {
            return this.abcache.LoadFromFile(bundle, hash, this.IngoreHash);
        }





        private string GetAssetBundePath(string bundle,string version)
        {
            if (string.IsNullOrEmpty(this.DownUrl))
            {
                return string.Empty;
            }
            return string.Format("{0}/{1}?v={2}", this.DownUrl, bundle, version);
        }

    }
}

